package module.modbus.ascii;

import common.BasicSerialPort;
import common.Const;
import gnu.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.nio.cs.ext.MS874;
import util.HexFormat;
import util.LRC;


import java.io.IOException;

import java.util.Arrays;
import java.util.TooManyListenersException;

/**
 * @author bingo
 * @Description
 * @Date 2018/8/12
 */
public  class ModbusAscii  extends BasicSerialPort{

    private Logger logger = LoggerFactory.getLogger(ModbusAscii.class);

    private String message;

    public String getMessage() {
        return message;
    }

    public SerialPort open(CommPortIdentifier commPortIdentifier)  {

        try {
            super.serialPort  = (SerialPort) commPortIdentifier.open(Object.class.getSimpleName(),2000);
            serialPort.notifyOnDataAvailable(true);
            serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_7, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
            serialPort.addEventListener(new SerialPortListener());
            //设置当有数据到达时唤醒监听接收线程
            serialPort.notifyOnDataAvailable(true) ;
            //设置当通信中断时唤醒中断线程
            serialPort.notifyOnBreakInterrupt(true);
        } catch (PortInUseException e) {
            e.printStackTrace();
        } catch (TooManyListenersException e) {
            e.printStackTrace();
        } catch (UnsupportedCommOperationException e) {
            e.printStackTrace();
        }
        return serialPort;
    }
    /***
     *   基于串口协议数据的发送
     *   @param value  具体发送的数据
     *   @param slaveId 主机号
     *   @param  methodCode 方法码
     *   @param  startOffset 起始地址
     * */
    public void send(int slaveId, int methodCode, int startOffset, short[] value){
        StringBuffer stringBuffer  = new StringBuffer();
        if(methodCode== Const.READ&&value.length==1){
            stringBuffer = read(slaveId,methodCode,startOffset,value[0]);

        }else if(methodCode==Const.SINGLE_WRITE&&value.length==1){
            stringBuffer = write(slaveId,methodCode,startOffset,value[0]);

        }else if(methodCode==Const.MULTI_WRITE&&value.length>=1){
            stringBuffer =   write(slaveId,methodCode,startOffset,value);

        }else {
            logger.info("数据未发送~~,功能码没找到,请查看数据格式是否正确");
        }
            String LRCCode = LRC.calcute(stringBuffer.toString());
            stringBuffer.append(LRCCode);
            stringBuffer.append("\r\n");
            String data = ":"+stringBuffer.toString();
            logger.info("ASCII形式发送的信息->{}",data);
            byte[] bys2 = data.getBytes();
            logger.info("ASCII字节信息->{}",Arrays.toString(bys2));
        if(serialPort!=null){
            try {
                outputStream = serialPort.getOutputStream();
                outputStream.write(bys2);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

/**
 *
 *  Modbus 从机返回
 *
 * */

    @Override
     public   String receive(){
        String receiveData=null;
        try {
            inputStream  = serialPort.getInputStream();
            int len = inputStream.available();
            byte[] bys  = new byte[len];
            while (len!=0){
                inputStream.read(bys);
                len = inputStream.available();
                receiveData = new String(bys);
                logger.info("ASCII受到返回信息->{}",receiveData);
            }
          } catch (IOException e) {
             e.printStackTrace();
           }finally {
               if(inputStream!=null){
                   try {
                       inputStream.close();
                   } catch (IOException e) {
                       e.printStackTrace();
                   }
               }
        }
        try{
            if(receiveData!=null){
                String receiveLRC = receiveData.substring(receiveData.length()-4,receiveData.length()-2);
                String calLRC = LRC.calcute(receiveData.substring(1,receiveData.length()-4));
                if(receiveLRC.equalsIgnoreCase(calLRC)){
                    logger.info("receiveLRC:{},calLRC:{},校验成功！",receiveLRC,calLRC);
                    String  code = receiveData.substring(3,5);
                    int methodCode = Integer.parseInt(code,16);
                    if(methodCode==Const.READ){
                        logger.info("开始组装返回数据");
                        int length = Integer.parseInt(receiveData.substring(5,7),16)/2;
                        for(int i=0;i<length/2;i++){
                            int beginIndex  =7+i*4;
                            int item = Integer.parseInt(receiveData.substring(beginIndex,beginIndex+4),16);
                            logger.info("item：{}",item);
                        }
                    }else if(methodCode==Const.MULTI_WRITE||methodCode==Const.SINGLE_WRITE){
                        logger.info("写请求~~~");
                    }else if(methodCode>=128){
                        logger.info("从机有错误！请派人去去维修");
                    }
                }else{
                    logger.info("receiveLRC:{},calLRC:{},校验失败！",receiveLRC,calLRC);
                }
            }
            else{
                logger.info("没有收到数据！！！");
            }

        }catch (Exception e){
            e.printStackTrace();
            logger.info("程序执行出现异常");
        }
        AsciiStartThread.isLock = false;
        message = receiveData;
        return receiveData;
    }

/**
 *  批量写
 * */

    private StringBuffer write(int slaveId, int methodCode, int startOffset, short[] value){
        StringBuffer stringBuffer = new StringBuffer();

        String hexSlaveId = Integer.toHexString(slaveId);
        stringBuffer.append(HexFormat.formatSimpple(hexSlaveId));

        String hexMethodCode = Integer.toHexString(methodCode);
        stringBuffer.append(HexFormat.formatSimpple(hexMethodCode));

        String hexStart = HexFormat.formatHex(Integer.toHexString(startOffset));
        stringBuffer.append(hexStart);
        String hexCount = Integer.toHexString(value.length);
        stringBuffer.append(HexFormat.formatHex(hexCount));
        String hexByteLength = Integer.toHexString(value.length*2);
        stringBuffer.append(HexFormat.formatSimpple(hexByteLength));
        for(short item:value){
            String hexValue = HexFormat.formatHex(Integer.toHexString(item));
            stringBuffer.append(hexValue);
        }
        return  stringBuffer;

    }
    /**
     *  单个写
     *
     * */
    private StringBuffer write(int slaveId, int methodCode, int startOffset, short value){

        return splice(slaveId,methodCode,startOffset,value);
    }
/**
 *
 *  此方法对应6号功能码，读单个数据
 * */

    private StringBuffer read(int slaveId, int methodCode, int startOffset, short value){

        return splice(slaveId,methodCode,startOffset,value);
    }

    private StringBuffer splice(int slaveId, int methodCode, int startOffset, short value){

        StringBuffer stringBuffer = new StringBuffer();

        String hexSlaveId = Integer.toHexString(slaveId);
        stringBuffer.append(HexFormat.formatSimpple(hexSlaveId));

        String hexMethodCode = Integer.toHexString(methodCode);
        stringBuffer.append(HexFormat.formatSimpple(hexMethodCode));

        String hexStart = HexFormat.formatHex(Integer.toHexString(startOffset));
        stringBuffer.append(hexStart);
        String hexValue = HexFormat.formatHex(Integer.toHexString(value));
        stringBuffer.append(hexValue);
        return  stringBuffer;
    }

    public void close(){
        if(serialPort!=null){
            serialPort.close();
            logger.info("串口已经关闭");
        }
    }




}
